var _this = this;

const { useState, useEffect, Fragment } = React;
const X = 'X';
const O = 'O';

const WINNING_PATTERNS = [7, 56, 448, // Horizontal
73, 146, 292, // Vertical
273, 84];

const Game = () => {
    const [player, setPlayer] = useState(X);
    const [patterns, setPatterns] = useState({ [X]: 0, [O]: 0 });
    const [winner, setWinner] = useState(null);
    const [rotated, setRotated] = useState(false);
    const [board, setBoard] = useState([[null, null, null], [null, null, null], [null, null, null]]);

    handleOnClick = (i, j) => {
        if (null === board[i][j]) {
            const state = {
                board: [...board],
                player: player === X ? O : X,
                patterns: patterns
            };

            state.board[i][j] = player;

            state.patterns[player] = state.patterns[player] |= Math.pow(2, i * 3 + j);

            state.winner = checkForWin(state.patterns);

            setBoard(state.board);
            setPlayer(state.player);
            setPatterns(state.patterns);
            setWinner(state.winner);

            if (state.winner || isBoardFull(board)) {
                setTimeout(() => {
                    setRotated(true);
                }, 1500);
            }
        }
    };

    handleOnPlayAgain = () => {
        setRotated(false);
        setTimeout(() => {
            setPlayer(X);
            setPatterns({ [X]: 0, [O]: 0 });
            setWinner(null);
            setRotated(false);
            setBoard([[null, null, null], [null, null, null], [null, null, null]]);
        }, 1000);
    };

    const checkForWin = patterns => {
        // Loop through all possible winning sets
        for (let i = 0; i < WINNING_PATTERNS.length; i++) {
            // Use bitwise AND to determind if the player's score
            // Holds a winning combination
            if ((WINNING_PATTERNS[i] & patterns[X]) === WINNING_PATTERNS[i]) return X;
            if ((WINNING_PATTERNS[i] & patterns[O]) === WINNING_PATTERNS[i]) return O;
        } // No winner
        return false;
    };

    const isBoardFull = board => {
        return !board.some((row, i) => {
            return row.some((col, j) => null === col);
        });
    };
    const getWinningPattern = () => {
        return WINNING_PATTERNS.find(pattern => (pattern & patterns[winner]) === pattern);
    };

    return React.createElement(
        'div',
        { className: `game ${rotated ? "rotated" : ""}` },
        React.createElement(Results, { winner: winner,
            draw: !winner && isBoardFull(board),
            onPlayAgain: handleOnPlayAgain
        }),
        React.createElement(Line, { show: winner, pattern: getWinningPattern() }),
        React.createElement(Board, { board: board, onClick: handleOnClick })
    );
};

const Circle = () => {
    return React.createElement(
        'svg',
        { className: 'pawn circle', viewBox: '0 0 128 128' },
        React.createElement('path', { d: 'M64,16A48,48 0 1,0 64,112A48,48 0 1,0 64,16' })
    );
};

const Times = () => React.createElement(
    'svg',
    { className: 'pawn times', viewBox: '0 0 128 128' },
    React.createElement('path', { d: 'M16,16L112,112' }),
    React.createElement('path', { d: 'M112,16L16,112' })
);

const Line = props => {
    const { pattern, show } = props;

    d = () => {
        return {
            7: `M 0,5 H 100`,
            56: `M 0,50 H 100`,
            448: `M 0,95 H 100`,
            73: `M 5,0 V 100`,
            146: `M 50,0 V 100`,
            292: `M 95,0 V 100`,
            273: `M 0,0 L 100,100`,
            84: `M 100,0 L 0,100`
        }[pattern];
    };
    return React.createElement(
        'svg',
        { className: `line ${show ? "visible" : ""}`, viewBox: '0 0 100 100' },
        React.createElement(
            'g',
            null,
            React.createElement('path', { d: d() })
        )
    );
};

const Cube = props => {
    const { value, onClick } = props;

    return React.createElement(
        'div',
        { className: `cube ${value ? "rotated" : ""}`,
            ref: ref => _this.ref = ref,
            onClick: onClick
        },
        ["top", "bottom", "left", "right", "front", "back"].map(face => React.createElement(
            'div',
            { className: face },
            face === 'back' && value === O && React.createElement(Circle, null),
            face === 'back' && value === X && React.createElement(Times, null)
        ))
    );
};

const Row = ({ children }) => React.createElement(
    'div',
    { className: 'row' },
    children
);

const Results = props => {
    const { winner, draw, onPlayAgain } = props;
    return React.createElement(
        'div',
        { className: 'results' },
        React.createElement(
            'div',
            { className: 'message' },
            React.createElement(
                'div',
                { className: 'symbol' },
                winner === X && React.createElement(Times, null),
                winner === O && React.createElement(Circle, null),
                draw && React.createElement(
                    Fragment,
                    null,
                    React.createElement(Times, null),
                    React.createElement(Circle, null)
                )
            ),
            React.createElement(
                'div',
                { className: 'text' },
                winner ? "Wins!" : "Draw!"
            )
        ),
        React.createElement(
            'div',
            { className: 'replay', onClick: onPlayAgain },
            '"Play Again"'
        )
    );
};

const Board = props => {
    const { board, onClick } = props;
    return React.createElement(
        'div',
        { className: 'board' },
        board.map((row, i) => React.createElement(
            Row,
            null,
            row.map((col, j) => React.createElement(Cube, { value: col, onClick: () => onClick(i, j) }))
        ))
    );
};

ReactDOM.render(React.createElement(Game, null), document.body);
